# items = [1, 5, 2, 1, 9, 1, 5, 10]
# it = iter(items) 使用iter将list转换成可手动迭代对象
# print(next(it))
# 在类中实现__iter__和__next__方法就可以实现迭代
# def myiter(n):
#     while n > 0:
#         yield n
#         n -= 1
#     print("迭代结束")
#
#
# for i in myiter(5):
#     print(i)
# class Node:
#     def __init__(self, value):
#         self._value = value
#         self._children = []
#
#     def __repr__(self):
#         return 'Node({!s})'.format(self._value)
#
#     def add_child(self, node):
#         self._children.append(node)
#
#     def __iter__(self):
#         return iter(self._children)
#
#     def depth_first(self):
#         yield self
#         for c in self:
#             yield from c.depth_first()
#
#
# # Example
# if __name__ == '__main__':
#     root = Node(0)
#     child1 = Node(1)
#     child2 = Node(2)
#     root.add_child(child1)
#     root.add_child(child2)
#     child1.add_child(Node(3))
#     child1.add_child(Node(4))
#     child2.add_child(Node(5))
#
#     for ch in root.depth_first():
#         print(ch)
#     # Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)
# 在一个类中实现__reverse__方法可以实现反向迭代操作
# 如果迭代对象没有实现__reverse__方法，则迭代对象会调用__iter__方法，然后调用__reverse__方法

# class Countdown:
#     def __init__(self, start):
#         self.start = start
#
#     # Forward iterator
#     def __iter__(self):
#         n = self.start
#         while n > 0:
#             yield n
#             n -= 1
#
#     # Reverse iterator
#     def __reversed__(self):
#         n = 1
#         while n <= self.start:
#             yield n
#             n += 1
#
#
# for rr in reversed(Countdown(30)):
#     print(rr)
# for rr in Countdown(30):
#     print(rr)
# 使用生成器函数时，如果想迭代某些外部的对象，可以将其实现为一个类，再将生成器写入类的__iter__方法中
# from collections import deque
#
#
# class linehistory:
#     def __init__(self, lines, histlen=3):
#         self.lines = lines
#         self.history = deque(maxlen=histlen)
#
#     def __iter__(self):
#         for lineno, line in enumerate(self.lines, 1):
#             self.history.append((lineno, line))
#             yield line
#
#     def clear(self):
#         self.history.clear()
#
#
# with open('somefile.txt') as f:
#     lines = linehistory(f)
#     for line in lines:
#         if 'python' in line:
#             for lineno, hline in lines.history:
#                 print('{}:{}'.format(lineno, hline), end='')
#
# 函数 itertools.islice() 适用于在迭代器和生成器上做切片操作。
# def count(n):
#     while True:
#         yield n
#         n += 1
#
#
# c = count(0)
# # c[10:20] 这种方法是不可行的
# import itertools
#
# for x in itertools.islice(c, 10, 20):
#     print(x)
# 跳过可迭代对象的开始部分。可以使用 itertools.dropwhile()，也可以使用itertools.islice()
# 迭代一个排列组合itertools.permutations()
# 迭代一个组合itertools.combinations()
# 迭代一个可重复的组合itertools.combinations_with_replacement()
# 迭代一个迭代器的所有子集itertools.chain()
# import itertools
# 迭代相关问题参考itertools
# li = ['a', 'b', 'c']
# # print(list(itertools.permutations(li)))
# # print(list(itertools.permutations(li, 2)))
# # print(list(itertools.combinations(li, 3)))
# # print(list(itertools.combinations(li, 2)))
# print(list(itertools.combinations_with_replacement(li, 3)))
# print(list(itertools.combinations_with_replacement(li, 2)))
# 使用enumerate()函数可以为可迭代对象附带一个编号，方便代码处理
# for ind, item in enumerate(li):
#     print(ind, item)
# # 也可以从1开始迭代
# for ind, item in enumerate(li, 1):
#     print(ind, item)
# 使用zip()可以同时迭代多个对象，按照短的哪个进行迭代
# a = [1, 2, 3]
# b = [4, 5, 6, 7]
# for x, y in zip(a, b):
#     print(x, y)
# 如果迭代长度不一致，则使用zip_longest()按照长的迭代对象进行迭代
# for x, y in itertools.zip_longest(a, b):
#     print(x, y)
# 同时可以给一个填充值
# for x, y in itertools.zip_longest(a, b, fillvalue=0):
#     print(x, y)
# chain()接受多个可迭代对象，并返回一个迭代器
# for x in itertools.chain(a, b):
# 日志文件：
# foo/
#     access-log-012007.gz
#     access-log-022007.gz
#     access-log-032007.gz
#     ...
#     access-log-012008
# bar/
#     access-log-092007.bz2
#     ...
#     access-log-022008
# 日志文件格式：
# 124.115.6.12 - - [10/Jul/2012:00:18:50 -0500] "GET /robots.txt ..." 200 71
# 210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /ply/ ..." 200 11875
# 210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /favicon.ico ..." 404 369
# 61.135.216.105 - - [10/Jul/2012:00:20:04 -0500] "GET /blog/atom.xml ..." 304 -
# 使用生成器函数实现日志文件解析
# import os
# import fnmatch
# import gzip
# import bz2
# import re
#
#
# def gen_find(filepat, top):
#     '''
#     Find all filenames in a directory tree that match a shell wildcard pattern
#     '''
#     for path, dirlist, filelist in os.walk(top):
#         for name in fnmatch.filter(filelist, filepat):
#             yield os.path.join(path, name)
#
#
# def gen_opener(filenames):
#     '''
#     Open a sequence of filenames one at a time producing a file object.
#     The file is closed immediately when proceeding to the next iteration.
#     '''
#     for filename in filenames:
#         if filename.endswith('.gz'):
#             f = gzip.open(filename, 'rt')
#         elif filename.endswith('.bz2'):
#             f = bz2.open(filename, 'rt')
#         else:
#             f = open(filename, 'rt')
#         yield f
#         f.close()
#
#
# def gen_concatenate(iterators):
#     '''
#     Chain a sequence of iterators together into a single sequence.
#     '''
#     for it in iterators:
#         yield from it
#
#
# def gen_grep(pattern, lines):
#     '''
#     Look for a regex pattern in a sequence of lines
#     '''
#     pat = re.compile(pattern)
#     for line in lines:
#         if pat.search(line):
#             yield line
#
#
# lognames = gen_find('access-log*', 'www')
# files = gen_opener(lognames)
# lines = gen_concatenate(files)
# pylines = gen_grep('(?i)python', lines)
# for line in pylines:
#     print(line)


# 不使用yield from:
# def generator():
#     for item in sub_generator():
#         yield item
#
#
# 使用yield from:
# def generator():
#     yield from sub_generator()

# 在展开嵌套的序列时，格外好用
#
# 合并两个排序序列并迭代：heapq.merge()是迭代器，并不会立刻生成列表，开销比较小
# import heapq
#
# nums1 = [1, 4, 7, 10]
# nums2 = [2, 5, 6, 11]
# nums3 = []
# for c in heapq.merge(nums1, nums2):
#     print(c)
# for a, b in zip(nums1, nums2):
#     if a < b:
#         nums3.append(a)
#         nums3.append(b)
#     else:
#         nums3.append(b)
#         nums3.append(a)
# print(nums3)
# 使用iter()替代while使用，尤其是在IO时，或者迭代器生成器中
